/*
 * =====================================================================================
 *
 *       Filename:  signal.hpp
 *
 *    Description:  Default Signal-handler for Drosera
 *
 *        Version:  1.0
 *        Created:  09.07.2012 14:29:37
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  akoww, 
 *   Organization:  
 *
 * =====================================================================================
 */

#ifndef SIGNAL_HPP_
#define SIGNAL_HPP_

#include <functional>
#include <utility>
#include <vector>

namespace Drosera {


template<class R, class... Args>
class Signal {

	public:
		
		/*
		 * Default constructor for creating a Signal
		 * 1) Empty Signal
		 * 2) Signal with function
		 * 3) rvalue reference
		 * 4) like 2) just as const
		 */

		Signal ( void ) {
		}

		Signal ( std::function<R (Args...)>& sig ) {
			m_sig.push_back ( sig );
		}

		Signal ( std::function<R (Args...)>&& sig ) {
			m_sig.push_back ( std::move ( sig ) );
		}

		Signal ( const std::function<R (Args...)>& sig ) {
			m_sig = sig;
		}

		/*
		 * Default copy-constructors for the Signals
		 * 1) rvalue reference copy constructor
		 * 2) normal reference constructor
		 * 3) same as above
		 */

		Signal ( Signal && sig ) {
			m_sig = std::move ( sig.getSignal() );
		}
		
		Signal ( Signal &sig ) {
			m_sig = sig.getSignal();
		}

		Signal ( const Signal &sig ) {
			m_sig = sig.getSignal();
		}


		/*
		 * Default destructor - nothing to do
		 */
		virtual ~Signal( void ) {};

		/*
		 * Copy operators
		 */

		void operator= ( const Signal &sig ) {
			m_sig = sig.getSignal();
		}

		void operator= ( Signal &sig ) {
			m_sig = sig.getSignal();
		}

		void operator= ( Signal &&sig ) {
			m_sig = std::move ( sig.getSignal() );
		}

		/*
		 * Execute command with arguments and return value
		 * 1) Execute all commands
		 * 2) Execute only one command
		 */

		void operator() ( Args... args ) {
			for ( unsigned int x = 0; x < m_sig.size(); x++ )
				m_sig[x]( args... );
		}

		void operator() ( unsigned int x, Args... args ) {
			if ( x >= m_sig.size() ) return;
			m_sig[x] ( args... );
		}

		/*
		 * Connecting a new function to the Signal
		 */

		void connect ( const std::function<R (Args...)> &sig ) {
			m_sig.push_back ( sig );
		}

		void connect ( std::function<R (Args...)>& sig ) {
			m_sig.push_back ( sig );
		}

		void connect ( std::function<R (Args...)>&& sig ) {
			m_sig.push_back ( std::move ( sig ));
		}

		/*
		 * Disconnect the Signal and clears it
		 */

		void disconnect ( void ) {
			m_sig.clear();
		}
		
		/*
		 * Return the signal as a function
		 */

		const std::function<R (Args...)>& getSignal ( void ) const {
			return m_sig;
		}

	private:
		std::vector<std::function<R (Args...)> > m_sig;

	protected:

};

template<class R>
class Signal<R> {

	public:

		/*
		 * Default constructor for creating a Signal
		 * 1) Empty Signal
		 * 2) Signal with function
		 * 3) rvalue reference
		 * 4) like 2) just as const
		 */

		Signal ( void ) {
		}

		Signal ( std::function<R ()>& sig ) {
			m_sig.push_back ( sig );
		}
		
		Signal ( const std::function<R ()>& sig ) {
			m_sig.push_back ( sig );
		}

		Signal ( std::function<R ()>&& sig ) {
			m_sig.push_back ( std::move ( sig ) );
		}

		/*
		 * Default copy-constructors for the Signals
		 * 1) rvalue reference copy constructor
		 * 2) normal reference constructor
		 * 3) same as above
		 */

		Signal ( Signal && sig ) {
			m_sig = std::move ( sig.getSignal() );
		}
		
		Signal ( Signal &sig ) {
			m_sig = sig.getSignal();
		}

		Signal ( const Signal &sig ) {
			m_sig = sig.getSignal();
		}


		/*
		 * Default destructor - nothing to do
		 */
		virtual ~Signal( void ) {};

		/*
		 * Copy operators
		 */

		void operator= ( const Signal &sig ) {
			m_sig = sig.getSignal();
		}

		void operator= ( Signal &sig ) {
			m_sig = sig.getSignal();
		}

		void operator= ( Signal &&sig ) {
			m_sig = std::move ( sig.getSignal() );
		}

		/*
		 * Execute command with arguments and return value
		 * 1) Execute all commands
		 * 2) Execute only one command
		 */

		void operator() ( void ) {
			for ( unsigned int x = 0; x < m_sig.size(); x++ )
				m_sig[x]();
		}

		void operator() ( unsigned int x ) {
			if ( x >= m_sig.size() ) return;
			m_sig[x]();
		}


		/*
		 * Connecting a new function to the Signal
		 */

		void connect ( const std::function<R ()> &sig ) {
			m_sig.push_back ( sig );
		}

		void connect ( std::function<R ()>& sig ) {
			m_sig.push_back ( sig );
		}

		void connect ( std::function<R ()>&& sig ) {
			m_sig.push_back ( std::move ( sig ));
		}

		/*
		 * Disconnect the Signal and clears it
		 */

		void disconnect ( void ) {
			m_sig.clear();
		}
		
		/*
		 * Return the signal as a function
		 */

		const std::function<R ()>& getSignal ( void ) const {
			return m_sig;
		}

	private:
		std::vector<std::function<R ()> > m_sig;

	protected:

};

}

#endif
